//
//  LGSModule.h
//  LogicSim
//
//  Created by Jeremy Pereira on 11/04/2012.
//  Copyright (c) 2012 Jeremy Pereira. All rights reserved.
//

#import "LGSNode.h"

/*!
 *  @brief key for the node array for JSON serialisation
 */
extern NSString* const LGS_NODES_ARRAY_KEY;
extern NSString* const LGS_INPUT_LABELS_KEY;
extern NSString* const LGS_OUTPUT_LABELS_KEY;
extern NSString* const LGS_CONNECTIONS_KEY;
extern NSString* const LGS_INPUT_MAPPINGS_KEY;
extern NSString* const LGS_OUTPUT_MAPPINGS_KEY;


/*!
 *  @brief A module is a grouping of nodes that can be treated as a single node.
 *
 *  Nodes within the module are referenced by label.  Each node added to the 
 *  module must have a unique label.
 *  @todo When connections are renamed, we don't handle the mappings yet.
 *  @todo When connections are deleted we don't handle the mappings yet.
 *  @todo When nodes are deleted we don't handle the mappings.
 *  @todo We can't connect until the mappings have been creted.
 */
@interface LGSModule : LGSNode

/*!
 *  @brief Add the nodes in the given set to the module.
 *
 *  If nodes exist with duplicate labels, they will be replaced in the module,
 *  although their nodes will not have their connections replaced.
 *  Do not add nodes to modules if they are already in another module.
 *  @param setOfNodes nodes to add to the module 
 */
-(void) addNodesFromSet: (NSSet*) setOfNodes;


/*!
 *  @brief Sets the input mappings.
 *
 *  Sets the mappings from an input name to the internal inputs to which it 
 *  connects.  The internal nodes must all exist with the input connections.
 *  If mappings exist already for the input name, they are destroyed.
 *  @param inputName The name of the module's input connection.
 *  @param internalInputs An array of LGSName with both a node and a connection. 
 *  The node and the input must exist.
 *  @return true if the input mappings are valid.
 */
-(bool) setInputMappingFrom: (LGSName*) inputName to: (NSArray*) internalInputs;

/*!
 *  @brief Sets an input mapping using strings instead of names.
 *
 *  This is a convenience method that converts all the strings to LGSNames and
 *  invokes -setInputMappingFrom:to:
 *  @param inputName Name of the module input as a string.
 *  @param internalInputs Array of strings of the form node.connection
 *  @return true if everything works ok znd the input and all strings in the 
 *  array are valid.
 */
-(bool) setInputMappingFromString: (NSString*) inputName
                        toStrings: (NSArray*) internalInputs;

/*!
 *  @brief Add a new input mapping.
 *
 *  This method adds an additional input mapping to the ones that already exist
 *  unless such a mapping already exists.
 *
 *  @param inputName The input on the module to be mapped.
 *  @param nodeNameWithConnection An LGSName consisting of a node and an input
 *  connection on the node.
 *  @return true if the input, node and node input all exist. False, if not.
 */
-(bool) addInputMappingFrom: (LGSName*) inputName
                 toNodeName: (LGSName*) nodeNameWithConnection;

/*!
 *  @brief Gets a list of the input mappings for a given input connection
 *
 *  @param inputName Name of the input connection.
 *  @return An array of the existing mappings (may be empty) or nil if the 
 *  name does not refer to an input connection.  Each mapping is an LGSName
 *  of the node and connection mapped to.
 */
-(NSArray*) inputMappingsFor: (LGSName*) inputName;

/*!
 *  @brief Add an output mapping.
 *
 *  Adds a mapping from an output name to the internal output to which it
 *  connects.  The internal node must exist with the output connection.
 *  @param outputName The name of the module's output connection.
 *  @param internalOutput A string of the form node.output.  The node
 *  and the output must exist.
 *  @return true if the output mapping is valid.
 */
-(bool) addOutputMappingFrom: (LGSName*) outputName
                          to: (LGSName*) internalOutput;
/*!
 *  @brief Add an output mapping using strings.
 *
 *  Adds a mapping from an output name as a string to the internal output 
 *  (specified as a string) to which it connects.  The internal node must exist 
 *  with the output connection.
 *  @param outputName The name of the module's output connection.
 *  @param internalOutput A string of the form node.output.  The node
 *  and the output must exist.
 *  @return true if the output mapping is valid.
 */
-(bool) addOutputMappingFromString: (NSString*) outputName
                          toString: (NSString*) internalOutput;

/*!
 *  @brief Change the name of one of the sub nodes off this module.
 *
 *  It is an error to try to change to the name of a node that already exists
 *  and an exception will be thrown.  Also, an exception will be thrown if 
 *  the node is not a subnode of this node.
 *  @param theNode The node whose name has already been changed.
 */
-(void) changeNameForNode: (LGSNode*) theNode;

@end
